#pragma once

#include "common/common.h"
#include "ipc/cthreadmutex.h"


using namespace PILO::Core::IPC;

namespace PILO 
{
    namespace Core
    {
        namespace Thread 
        {
            enum ThreadPriorityEnumeration
            {
                EnumPriorityIdel,
                EnumPriorityLowest,
                EnumPriorityBelowNormal,
                EnumPriorityNormal,
                EnumPriorityAboveNormal,
                EnumPriorityHighest,
                EnumPriorityCritical,
                EnumPriorityInvalid,
            };

            enum ThreadStateEnumeration
            {
                //Normal
                EnumStateNotStarted        = 0, //The initial state of a thread, once it changed it never changed back.
                EnumStatePreparing         = 1, //The time between create a thread and onRun() is called
                EnumStateRunning           = 2, //The hole lifetime of onRun()
                EnumStateFinished          = 3, //Thread transit to this state after onRun() is returned. This is the last phase of state.for detached threads. 
                EnumStateFinishedAndJoined = 4, //Thread transit to this state after it was joined by waitThread successfully. 
                                                //This  is the last phase of state.for joinable threads.

                //Abnormal
                EnumStateAborted           = 0x80000003,
                EnumStateAbortedAndJoined  = 0x80000004,
            };

            class CAbstractThread
            {
            public:               

                CAbstractThread();
                virtual ~CAbstractThread() {}

                //Allow RunableCallback to set stutus and call other related method of thread class
                friend THREAD_ROUTINE_RETURN_TYPE THREAD_ROUTINE_CALL ThreadStartRoutineCallback(void* param);

                //Thread Creation Parameters
                size_t threadCreationStackSize() const 
                { 
                    return _m_creationStackSize; 
                }
                INT32 setThreadCreationStackSize(size_t s)
                {
                    if (s > MC_LIMIT_THREAD_MAX_STACK_SIZE) 
                    {
                        return EC_REACH_UPPER_LIMIT;
                    }
                    _m_creationStackSize = s;
                    return EC_OK;
                }

                BOOL threadCreationDetachedState() const 
                { 
                    return _m_creationDetachState; 
                }
                INT32 setThreadCreationDetachedState(BOOL isEnable);

                //Thread runtime Parameters
                INT32 getPriority(ThreadPriorityEnumeration& refPri);
                INT32 setPriority(ThreadPriorityEnumeration pri);

                ThreadStateEnumeration state() const
                {
                    return _m_state;
                }

                //Thread operation
                INT32 startThread();
                INT32 waitThread();

                //Thread Status
                BOOL isDetached() const
                {
                    return _m_isDetached;               
                }


                //////////////////////////////////////////////////////////////////////////////////////////////
                /// Retrieve result of this thread                                                         ///
                ///                                                                                        ///
                ///      Call this method when thread is finished,                                         ///
                ///      it will store the thread result in the parameter.                                 ///
                ///      @param      resultCode: A reference to resultCode, use to store the result.       ///
                ///      @return     return E_OK on success;                                               ///
                ///                  return E_THREAD_ABORTED if this thread is killed.                     ///
                ///                  return E_THREAD_STATE_ERROR if this thread is still running or not    ///
                ///                  started yet                                                           ///
                ///      @see        killThread()                                                          ///
                ///      @note       Call this method after the thread has been start or E_THREAD_ABORTED  ///
                ///                  is returned.                                                          ///
                //////////////////////////////////////////////////////////////////////////////////////////////
                INT32 getResult(INT32& resultCode);
                

                //Thread command
                BOOL terminationRequired();
                INT32 setTerminationRequired();

                INT32 detach();
                INT32 killThread();

                

                static void sleep(unsigned long);
                static void msleep(unsigned long);
                static void usleep(unsigned long);


            protected:
                
                //This method is the routine of the thread, must be rewrote
                virtual INT32 onRun()=0;
                //This method will be called when run() is Finished normally
                virtual void onFinished() 
                {
                }
                //This method will be called just before thread is killed.
                virtual void onThreadPreKill() 
                {
                }
                //This method will be called just after thread is killed.
                virtual void onThreadPostKill()
                {
                }

                //Thread parameters
                size_t  _m_creationStackSize;
                BOOL    _m_creationDetachState;

                //Thread status
                BOOL    _m_isDetached;
                volatile ThreadStateEnumeration _m_state;
                
                //Thread command
                BOOL    _m_bTerminationRequired;

                //Result code
                INT32   _m_resultCode;

                CThreadMutex    _m_lock;


#           ifdef WINDOWS
                HANDLE    _m_threadHandle;
                unsigned  _m_threadID;                

#           else
                pthread_t _m_threadID;

#           endif
            private:
                BOOL _isStopped() const {
                    if (EnumStateNotStarted == _m_state) {
                        return TRUE;
                    }

                    if (_m_isDetached) {
                        if ((EnumStateFinished == _m_state) || 
                            (EnumStateAborted == _m_state)) {
                                return TRUE;
                        }
                    } else {
                        if ((EnumStateFinishedAndJoined == _m_state) || 
                            (EnumStateAbortedAndJoined == _m_state)) {
                                return TRUE;
                        }

                    }
                    return FALSE;
                }

                INT32 _waitForStateTransitionFromPreparingToRunning()
                {
                    while (EnumStatePreparing == _m_state) {
                        CAbstractThread::sleep(0);   
                    }

                    if (EnumStateRunning == _m_state) {
                        return EC_OK;
                    }
                    
                    return EC_THREAD_STATE_ERROR;

                }
                M_DISABLE_COPY(CAbstractThread)
            };
        }
    }    
}
